home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / pointburst.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  13.4 KB  |  563 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1997, 1998.  */
  3.  
  4. /* This program is freely distributable without licensing fees 
  5.    and is provided without guarantee or warrantee expressed or 
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. /* This example demonstrates how to render particle effects
  9.    with OpenGL.  A cloud of pinkish/orange particles explodes with the
  10.    particles bouncing off the ground.  When the SGIS_point_parameters
  11.    is present (supported on SGI's InfiniteReality hardware), the
  12.    particle size is attenuated based on eye distance. */
  13.  
  14. /* Now pointburst.c is extended to support the multi-vendor
  15.    EXT_point_parameters extension that has the same interface as the
  16.    SGIS extension (modulo the SGIS suffix/prefix).  NVidia's Release 2
  17.    OpenGL ICD driver supports the EXT_point_parameters extension. */
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <math.h>       /* for cos(), sin(), and sqrt() */
  23. #ifdef _WIN32
  24. #include <windows.h>    /* for wglGetProcAddress */
  25. #endif
  26. #include <GL/glut.h>
  27.  
  28. /* Some <math.h> files do not define M_PI... */
  29. #ifndef M_PI
  30. #define M_PI 3.14159265358979323846
  31. #endif
  32.  
  33. #if 0  /* For debugging. */
  34. #undef GL_SGIS_point_parameters
  35. #endif
  36.  
  37. #if defined(GL_SGIS_point_parameters) && !defined(GL_EXT_point_parameters)
  38. /* Use the EXT point parameters interface for the SGIS implementation. */
  39. #define GL_POINT_SIZE_MIN_EXT GL_POINT_SIZE_MIN_SGIS
  40. #define GL_POINT_SIZE_MAX_EXT GL_POINT_SIZE_MAX_SGIS
  41. #define GL_POINT_FADE_THRESHOLD_SIZE_EXT GL_POINT_FADE_THRESHOLD_SIZE_SGIS
  42. #define GL_DISTANCE_ATTENUATION_EXT GL_DISTANCE_ATTENUATION_SGIS
  43. #define glPointParameterfEXT glPointParameterfSGIS
  44. #define glPointParameterfvEXT glPointParameterfvSGIS
  45. #define GL_EXT_point_parameters 1
  46. #endif
  47.  
  48. #if !defined(GL_EXT_point_parameters)
  49. #define GL_POINT_SIZE_MIN_EXT               0x8126
  50. #define GL_POINT_SIZE_MAX_EXT               0x8127
  51. #define GL_POINT_FADE_THRESHOLD_SIZE_EXT    0x8128
  52. #define GL_DISTANCE_ATTENUATION_EXT         0x8129
  53. #ifdef _WIN32
  54. /* Curse Microsoft for the insanity of wglGetProcAddress. */
  55. typedef void (APIENTRY * PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);
  56. typedef void (APIENTRY * PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);
  57. #define GL_EXT_point_parameters 1
  58. #endif
  59. #endif
  60.  
  61. #ifdef _WIN32
  62. PFNGLPOINTPARAMETERFEXTPROC glPointParameterfEXT;
  63. PFNGLPOINTPARAMETERFVEXTPROC glPointParameterfvEXT;
  64. #endif
  65.  
  66. int hasPointParameters;
  67.  
  68. static GLfloat angle = -150;   /* in degrees */
  69. static int spin = 0;
  70. static int moving, begin;
  71. static int newModel = 1;
  72. static float time;
  73. static int repeat = 1;
  74. int useMipmaps = 1;
  75. int linearFiltering = 1;
  76. int useTexture = 1;
  77.  
  78. #if GL_EXT_point_parameters
  79. static GLfloat constant[3] = { 1/5.0, 0.0, 0.0 };
  80. static GLfloat linear[3] = { 0.0, 1/5.0, 0.0 };
  81. static GLfloat quadratic[3] = { 0.25, 0.0, 1/60.0 };
  82. #endif
  83.  
  84. #define MAX_POINTS 2000
  85.  
  86. static int numPoints = 500;
  87.  
  88. static GLfloat pointList[MAX_POINTS][3];
  89. static GLfloat pointTime[MAX_POINTS];
  90. static GLfloat pointVelocity[MAX_POINTS][2];
  91. static GLfloat pointDirection[MAX_POINTS][2];
  92. static int colorList[MAX_POINTS];
  93. static int animate = 1, motion = 0;
  94.  
  95. static GLfloat colorSet[][4] = {
  96.   /* Shades of red. */
  97.   { 0.7, 0.2, 0.4, 0.5 },
  98.   { 0.8, 0.0, 0.7, 0.5 },
  99.   { 1.0, 0.0, 0.0, 0.5 },
  100.   { 0.9, 0.3, 0.6, 0.5 },
  101.   { 1.0, 0.4, 0.0, 0.5 },
  102.   { 1.0, 0.0, 0.5, 0.5 },
  103. };
  104.  
  105. #define NUM_COLORS (sizeof(colorSet)/sizeof(colorSet[0]))
  106.  
  107. #define DEAD (NUM_COLORS+1)
  108.  
  109.  
  110. #if 0  /* drand48 might be better on Unix machines */
  111. #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * drand48())
  112. #else
  113. static float float_rand(void) { return rand() / (float) RAND_MAX; }
  114. #define RANDOM_RANGE(lo, hi) ((lo) + (hi - lo) * float_rand())
  115. #endif
  116.  
  117. #define MEAN_VELOCITY 3.0
  118. #define GRAVITY 2.0
  119. #define TIME_DELTA 0.025  /* The speed of time. */
  120.  
  121. /* Modeling units of ground extent in each X and Z direction. */
  122. #define EDGE 12
  123.  
  124. void
  125. makePointList(void)
  126. {
  127.   float angle, velocity, direction;
  128.   int i;
  129.  
  130.   motion = 1;
  131.   for (i=0; i<numPoints; i++) {
  132.     pointList[i][0] = 0.0;
  133.     pointList[i][1] = 0.0;
  134.     pointList[i][2] = 0.0;
  135.     pointTime[i] = 0.0;
  136.     angle = (RANDOM_RANGE(60.0, 70.0)) * M_PI/180.0;
  137.     direction = RANDOM_RANGE(0.0, 360.0) * M_PI/180.0;
  138.     pointDirection[i][0] = cos(direction);
  139.     pointDirection[i][1] = sin(direction);
  140.     velocity = MEAN_VELOCITY + RANDOM_RANGE(-0.8, 1.0);
  141.     pointVelocity[i][0] = velocity * cos(angle);
  142.     pointVelocity[i][1] = velocity * sin(angle);
  143.     colorList[i] = rand() % NUM_COLORS;
  144.   }
  145.   time = 0.0;
  146. }
  147.  
  148. void
  149. updatePointList(void)
  150. {
  151.   float distance;
  152.   int i;
  153.  
  154.   motion = 0;
  155.   for (i=0; i<numPoints; i++) {
  156.     distance = pointVelocity[i][0] * time;
  157.  
  158.     /* X and Z */
  159.     pointList[i][0] = pointDirection[i][0] * distance;
  160.     pointList[i][2] = pointDirection[i][1] * distance;
  161.  
  162.     /* Z */
  163.     pointList[i][1] =
  164.       (pointVelocity[i][1] - 0.5 * GRAVITY * pointTime[i])*pointTime[i];
  165.  
  166.     /* If we hit the ground, bounce the point upward again. */
  167.     if (pointList[i][1] <= 0.0) {
  168.       if (distance > EDGE) {
  169.         /* Particle has hit ground past the distance duration of
  170.        the particles.  Mark particle as dead. */
  171.     colorList[i] = NUM_COLORS;  /* Not moving. */
  172.     continue;
  173.       }
  174.  
  175.       pointVelocity[i][1] *= 0.8;  /* 80% of previous up velocity. */
  176.       pointTime[i] = 0.0;  /* Reset the particles sense of up time. */
  177.     }
  178.     motion = 1;
  179.     pointTime[i] += TIME_DELTA;
  180.   }
  181.   time += TIME_DELTA;
  182.   if (!motion && !spin) {
  183.     if (repeat) {
  184.       makePointList();
  185.     } else {
  186.       glutIdleFunc(NULL);
  187.     }
  188.   }
  189. }
  190.  
  191. void
  192. idle(void)
  193. {
  194.   updatePointList();
  195.   if (spin) {
  196.     angle += 0.3;
  197.     newModel = 1;
  198.   }
  199.   glutPostRedisplay();
  200. }
  201.  
  202. void
  203. visible(int vis)
  204. {
  205.   if (vis == GLUT_VISIBLE) {
  206.     if (animate && (motion || spin)) {
  207.       glutIdleFunc(idle);
  208.     }
  209.   } else {
  210.     glutIdleFunc(NULL);
  211.   }
  212. }
  213.  
  214. void
  215. recalcModelView(void)
  216. {
  217.   glPopMatrix();
  218.   glPushMatrix();
  219.   glRotatef(angle, 0.0, 1.0, 0.0);
  220.   newModel = 0;
  221. }
  222.  
  223. void
  224. redraw(void)
  225. {
  226.   int i;
  227.  
  228.   glDepthMask(GL_TRUE);
  229.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  230.   if (newModel)
  231.     recalcModelView();
  232.  
  233.   /* Draw the floor. */
  234.   if (useTexture) {
  235.     glEnable(GL_TEXTURE_2D);
  236.   }
  237.   glColor3f(0.5, 1.0, 0.5);
  238.   glBegin(GL_QUADS);
  239.     glTexCoord2f(0.0, 0.0);
  240.     glVertex3f(-EDGE, -0.05, -EDGE);
  241.     glTexCoord2f(20.0, 0.0);
  242.     glVertex3f(EDGE, -0.05, -EDGE);
  243.     glTexCoord2f(20.0, 20.0);
  244.     glVertex3f(EDGE, -0.05, EDGE);
  245.     glTexCoord2f(0.0, 20.0);
  246.     glVertex3f(-EDGE, -0.05, EDGE);
  247.   glEnd();
  248.  
  249.   /* Allow particles to blend with each other. */
  250.   glDepthMask(GL_FALSE);
  251.  
  252.   if (useTexture) {
  253.     glDisable(GL_TEXTURE_2D);
  254.   }
  255.   glBegin(GL_POINTS);
  256.     for (i=0; i<numPoints; i++) {
  257.       /* Draw alive particles. */
  258.       if (colorList[i] != DEAD) {
  259.         glColor4fv(colorSet[colorList[i]]);
  260.         glVertex3fv(pointList[i]);
  261.       }
  262.     }
  263.   glEnd();
  264.  
  265.   glutSwapBuffers();
  266. }
  267.  
  268. /* ARGSUSED2 */
  269. void
  270. mouse(int button, int state, int x, int y)
  271. {
  272.   /* Scene can be spun around Y axis using left
  273.      mouse button movement. */
  274.   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  275.     moving = 1;
  276.     begin = x;
  277.   }
  278.   if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
  279.     moving = 0;
  280.   }
  281. }
  282.  
  283. /* ARGSUSED1 */
  284. void
  285. mouseMotion(int x, int y)
  286. {
  287.   if (moving) {
  288.     angle = angle + (x - begin);
  289.     begin = x;
  290.     newModel = 1;
  291.     glutPostRedisplay();
  292.   }
  293. }
  294.  
  295. void
  296. menu(int option)
  297. {
  298.   switch (option) {
  299.   case 0:
  300.     makePointList();
  301.     break;
  302. #if GL_EXT_point_parameters
  303.   case 1:
  304.     if (hasPointParameters) {
  305.       glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, constant);
  306.     }
  307.     break;
  308.   case 2:
  309.     if (hasPointParameters) {
  310.       glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, linear);
  311.     }
  312.     break;
  313.   case 3:
  314.     if (hasPointParameters) {
  315.       glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, quadratic);
  316.     }
  317.     break;
  318. #endif
  319.   case 4:
  320.     glEnable(GL_BLEND);
  321.     break;
  322.   case 5:
  323.     glDisable(GL_BLEND);
  324.     break;
  325. #if GL_EXT_point_parameters
  326.   case 6:
  327.     if (hasPointParameters) {
  328.       glPointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0);
  329.     }
  330.     break;
  331.   case 7:
  332.     if (hasPointParameters) {
  333.       glPointParameterfEXT(GL_POINT_FADE_THRESHOLD_SIZE_EXT, 10.0);
  334.     }
  335.     break;
  336. #endif
  337.   case 8:
  338.     glEnable(GL_POINT_SMOOTH);
  339.     break;
  340.   case 9:
  341.     glDisable(GL_POINT_SMOOTH);
  342.     break;
  343.   case 10:
  344.     glPointSize(2.0);
  345.     break;
  346.   case 11:
  347.     glPointSize(4.0);
  348.     break;
  349.   case 12:
  350.     glPointSize(8.0);
  351.     break;
  352.   case 18:
  353.     glPointSize(16.0);
  354.     break;
  355.   case 13:
  356.     spin = 1 - spin;
  357.     if (animate && (spin || motion)) {
  358.       glutIdleFunc(idle);
  359.     } else {
  360.       glutIdleFunc(NULL);
  361.     }
  362.     break;
  363.   case 14:
  364.     numPoints = 200;
  365.     break;
  366.   case 15:
  367.     numPoints = 500;
  368.     break;
  369.   case 16:
  370.     numPoints = 1000;
  371.     break;
  372.   case 17:
  373.     numPoints = 2000;
  374.     break;
  375.   case 19:
  376.     useTexture = !useTexture;
  377.     break;
  378.   case 666:
  379.     exit(0);
  380.   }
  381.   glutPostRedisplay();
  382. }
  383.  
  384. /* ARGSUSED1 */
  385. void
  386. key(unsigned char c, int x, int y)
  387. {
  388.   switch (c) {
  389.   case 13:
  390.     animate = 1 - animate;  /* toggle. */
  391.     if (animate && (motion || spin)) {
  392.       glutIdleFunc(idle);
  393.     } else {
  394.       glutIdleFunc(NULL);
  395.     }
  396.     break;
  397.   case ' ':
  398.     animate = 1;
  399.     makePointList();
  400.     glutIdleFunc(idle);
  401.     break;
  402.   case 27:
  403.     exit(0);
  404.   }
  405. }
  406.  
  407. /* Nice floor texture tiling pattern. */
  408. static char *circles[] = {
  409.   "....xxxx........",
  410.   "..xxxxxxxx......",
  411.   ".xxxxxxxxxx.....",
  412.   ".xxx....xxx.....",
  413.   "xxx......xxx....",
  414.   "xxx......xxx....",
  415.   "xxx......xxx....",
  416.   "xxx......xxx....",
  417.   ".xxx....xxx.....",
  418.   ".xxxxxxxxxx.....",
  419.   "..xxxxxxxx......",
  420.   "....xxxx........",
  421.   "................",
  422.   "................",
  423.   "................",
  424.   "................",
  425. };
  426.  
  427. static void
  428. makeFloorTexture(void)
  429. {
  430.   GLubyte floorTexture[16][16][3];
  431.   GLubyte *loc;
  432.   int s, t;
  433.  
  434.   /* Setup RGB image for the texture. */
  435.   loc = (GLubyte*) floorTexture;
  436.   for (t = 0; t < 16; t++) {
  437.     for (s = 0; s < 16; s++) {
  438.       if (circles[t][s] == 'x') {
  439.         /* Nice blue. */
  440.         loc[0] = 0x1f;
  441.         loc[1] = 0x1f;
  442.         loc[2] = 0x8f;
  443.       } else {
  444.         /* Light gray. */
  445.         loc[0] = 0xca;
  446.         loc[1] = 0xca;
  447.         loc[2] = 0xca;
  448.       }
  449.       loc += 3;
  450.     }
  451.   }
  452.  
  453.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  454.  
  455.   if (useMipmaps) {
  456.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  457.       GL_LINEAR_MIPMAP_LINEAR);
  458.     gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 16, 16,
  459.       GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
  460.   } else {
  461.     if (linearFiltering) {
  462.       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  463.     } else {
  464.       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  465.     }
  466.     glTexImage2D(GL_TEXTURE_2D, 0, 3, 16, 16, 0,
  467.       GL_RGB, GL_UNSIGNED_BYTE, floorTexture);
  468.   }
  469. }
  470.  
  471. int
  472. main(int argc, char **argv)
  473. {
  474.   int i;
  475.  
  476.   glutInit(&argc, argv);
  477.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
  478.  
  479.   for (i=1; i<argc; i++) {
  480.     if(!strcmp("-noms", argv[i])) {
  481.       glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  482.       printf("forcing no multisampling\n");
  483.     } else if(!strcmp("-nomipmaps", argv[i])) {
  484.       useMipmaps = 0;
  485.     } else if(!strcmp("-nearest", argv[i])) {
  486.       linearFiltering = 0;
  487.     }
  488.   }
  489.  
  490.   glutCreateWindow("point burst");
  491.  
  492.   hasPointParameters = glutExtensionSupported("GL_SGIS_point_parameters") ||
  493.     glutExtensionSupported("GL_EXT_point_parameters");
  494. #ifdef _WIN32
  495.   if (hasPointParameters) {
  496.     glPointParameterfEXT = (PFNGLPOINTPARAMETERFEXTPROC)
  497.       wglGetProcAddress("glPointParameterfEXT");
  498.     glPointParameterfvEXT = (PFNGLPOINTPARAMETERFVEXTPROC)
  499.       wglGetProcAddress("glPointParameterfvEXT");
  500.     printf("has point parameters extension!\n");
  501.   } else {
  502.     printf("does NOT have point parameters extension!\n");
  503.   }
  504. #endif
  505.  
  506.   glutDisplayFunc(redraw);
  507.   glutMouseFunc(mouse);
  508.   glutMotionFunc(mouseMotion);
  509.   glutVisibilityFunc(visible);
  510.   glutKeyboardFunc(key);
  511.   glutCreateMenu(menu);
  512.   glutAddMenuEntry("Reset time", 0);
  513.   glutAddMenuEntry("Constant", 1);
  514.   glutAddMenuEntry("Linear", 2);
  515.   glutAddMenuEntry("Quadratic", 3);
  516.   glutAddMenuEntry("Blend on", 4);
  517.   glutAddMenuEntry("Blend off", 5);
  518.   glutAddMenuEntry("Threshold 1", 6);
  519.   glutAddMenuEntry("Threshold 10", 7);
  520.   glutAddMenuEntry("Point smooth on", 8);
  521.   glutAddMenuEntry("Point smooth off", 9);
  522.   glutAddMenuEntry("Point size 2", 10);
  523.   glutAddMenuEntry("Point size 4", 11);
  524.   glutAddMenuEntry("Point size 8", 12);
  525.   glutAddMenuEntry("Point size 16", 18);
  526.   glutAddMenuEntry("Toggle spin", 13);
  527.   glutAddMenuEntry("200 points", 14);
  528.   glutAddMenuEntry("500 points", 15);
  529.   glutAddMenuEntry("1000 points", 16);
  530.   glutAddMenuEntry("2000 points", 17);
  531.   glutAddMenuEntry("Toggle texture", 19);
  532.   glutAddMenuEntry("Quit", 666);
  533.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  534.  
  535.   glEnable(GL_DEPTH_TEST);
  536.   glEnable(GL_POINT_SMOOTH);
  537.   glEnable(GL_BLEND);
  538.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  539.   glPointSize(8.0);
  540. #if GL_EXT_point_parameters
  541.   if (hasPointParameters) {
  542.     glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, quadratic);
  543.   }
  544. #endif
  545.  
  546.   glMatrixMode(GL_PROJECTION);
  547.   gluPerspective( /* field of view in degree */ 40.0,
  548.   /* aspect ratio */ 1.0,
  549.     /* Z near */ 0.5, /* Z far */ 40.0);
  550.   glMatrixMode(GL_MODELVIEW);
  551.   gluLookAt(0.0, 1.0, 8.0, /* eye location */
  552.     0.0, 1.0, 0.0,      /* center is at (0,0,0) */
  553.     0.0, 1.0, 0.);      /* up is in postivie Y direction */
  554.   glPushMatrix();       /* dummy push so we can pop on model
  555.                            recalc */
  556.  
  557.   makePointList();
  558.   makeFloorTexture();
  559.  
  560.   glutMainLoop();
  561.   return 0;             /* ANSI C requires main to return int. */
  562. }
  563.